package webx;

import stdx.Utils;
import webx.http.Http;
import stdx.BaseException;
import webx.http.HttpRequest;
import webx.http.HttpResponse;
import java.util.concurrent.ConcurrentHashMap;

public class Resource extends WebApp{
	static class FileItem{
		public long ctime;
		public byte[] data;
		public String etag;

		FileItem(byte[] buffer){
			data = buffer;

			if (data == null){
				etag = null;
			}
			else{
				int hash = 0;

				for (byte i : data) {
					hash = 31 * hash + 128 + i;
				}

				ctime = System.currentTimeMillis();
				etag = String.format("%d:%08d:%08d", systime, Math.abs(hash) % 100000000, data.length % 100000000);
			}
		}
		public boolean isTimeout(){
			return ctime + 3000L < System.currentTimeMillis();
		}
	}

	String rootpath = null;
	static final long systime = System.currentTimeMillis() / 1000L;
	static ConcurrentHashMap<String, FileItem> cachemap = new ConcurrentHashMap<String, FileItem>(1000);

	public Resource(){
	}
	public Resource(String path){
		rootpath = path;
	}
	public Resource(Class context){
		this(context, "webapp");
	}
	public Resource(Class context, String typename){
		rootpath = context.getPackage().getName().replaceAll("[.]", "/") + "/" + typename;
	}
	public boolean notModified(String ctag, String stag){
		if (Utils.IsEmpty(ctag)) return false;

		int pos = ctag.indexOf(':');

		if (pos < 8) return false;

		try{
			if (systime < Long.parseLong(ctag.substring(0, pos))) return true;
		}
		catch(Exception e){
			LogFile.Error(e);

			return false;
		}

		return ctag.equals(stag);
	}
	public String getContype(String path) throws Exception{
		int pos = path.lastIndexOf('.');
		String type = WebApp.GetMimeType(pos > 0 ? path.substring(pos + 1) : "html");

		if (type.startsWith("text/")){
			type += ";charset=" + Http.GetCharset();
		}

		return type;
	}
	public String getPath(HttpRequest request) throws Exception{
		String path = request.get("path");

		if (Utils.IsEmpty(path) || path.indexOf("..") >= 0) throw BaseException.PARAMERR;

		if (rootpath == null){
			path = "/" + request.getPath().substring(0, request.getPath().lastIndexOf('/')) + "/webapp/" + path;
		}
		else{
			path = "/" + rootpath + "/" + path;
		}

		return path.replaceAll("//", "/");
	}
	public void process(HttpRequest request, HttpResponse response) throws Exception{
		String path = getPath(request);
		FileItem file = cachemap.get(path);

		response.setHeader("Content-Type", getContype(path));

		if (file == null || file.isTimeout()){
			file = new FileItem(Utils.GetResourceContent(this.getClass(), path));

			if (file.data == null){
				response.setStatus(404);
				return;
			}

			cachemap.put(path, file);
		}

		String etag = request.getHeader("If-None-Match");

		if (notModified(etag, file.etag)){
			response.setHeader("ETag", etag);
			response.setStatus(304);
		}
		else{
			response.setHeader("ETag", file.etag);
			response.setBody(file.data);
		}
	}
}